#pragma once

struct D3DXFRAME_EXTENDED;
struct D3DXMESHCONTAINER_EXTENDED;

// Forward decl.:
class CXFileInstance;

/**
 * \class CXFileEntity
 * \brief Loads a .x file and maintains the heirarchy
 * \author Keith Ditchburn \date 17 July 2005
*/
class CXFileEntity {

	friend class CXFileInstance;

private:
	LPD3DXFRAME                 m_frameRoot;
    LPD3DXANIMATIONCONTROLLER   m_animController;
	
	// Them bones
	D3DXMATRIX *m_boneMatrices;
	UINT m_maxBones;

	// The default world tramsform for the object (for correcting scale, rotation issues):
	D3DXMATRIX                 m_mxWorld;

	D3DXMESHCONTAINER_EXTENDED* m_firstMesh;

	// Bounding sphere
	D3DXVECTOR3 m_sphereCentre;
	float m_sphereRadius;

	// Animation variables
	/*
	UINT m_currentAnimationSet;	
	UINT m_numAnimationSets;
	DWORD m_currentTrack;
	float m_currentTime;
	float m_speedAdjust;
	*/

	//void CloneFrameHierarchy( LPD3DXFRAME pFrameSrc, LPD3DXFRAME* pFrameDest ) const;
	//void FreeFrameHierarchy(LPD3DXFRAME pFrame);

	//void UpdateFrameMatrices(const D3DXFRAME *frameBase, const D3DXMATRIX *parentMatrix);
	//void DrawFrame(LPDIRECT3DDEVICE9 device,LPD3DXFRAME frame) const;
	//void DrawMeshContainer(LPDIRECT3DDEVICE9 device,LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase) const;

public:
	CXFileEntity(void);
	~CXFileEntity(void);

	HRESULT Clone( LPDIRECT3DDEVICE9 device, CXFileInstance *&fileInstance );
	HRESULT InitBones( LPDIRECT3DDEVICE9 device );

	HRESULT LoadXFile(LPDIRECT3DDEVICE9 device,const WCHAR* filename);
	void SetupBoneMatrices(LPDIRECT3DDEVICE9 device,D3DXFRAME_EXTENDED *pFrame, LPD3DXMATRIX pParentMatrix);
	//void FrameMove(float elapsedTime,const D3DXMATRIX *matWorld);
	//void Render(LPDIRECT3DDEVICE9 device) const;
	//void SetAnimationSet(UINT index);
	void GetBoundingSphere(D3DXVECTOR3* centre,float *radius) const {*centre=m_sphereCentre;*radius=m_sphereRadius;}

    D3DXMATRIX  GetWorldTransform();
    void        SetWorldTransform( const D3DXMATRIX * pmxWorld );

	//void NextAnimation();

	inline UINT GetMaxBones() const {return m_maxBones;}

};



/**
 * \class CXFileInstance
 * \brief Represents an instance of a .X model loaded from file
 * \brief into a CXFileEntity.
 * \author Mike Blackney \date 15 Oct 2006
*/
class CXFileInstance {

	friend class CXFileEntity;

protected:
	CXFileEntity              *m_pFileEntity; // Pointer to the file entity
    D3DXMATRIX                 m_mxWorld; // Position for this instance
    LPD3DXANIMATIONCONTROLLER  m_pAC; // Animation controller for this instance
	LPDIRECT3DDEVICE9		   m_pDevice; // The Direct3d device.

	UINT m_currentAnimationSet;	
	UINT m_numAnimationSets;
	DWORD m_currentTrack;
	float m_currentTime;
	float m_speedAdjust;

private:
    virtual HRESULT     Setup( LPD3DXANIMATIONCONTROLLER pAC ); // Initialise
	
			void UpdateFrameMatrices(const D3DXFRAME *frameBase, const D3DXMATRIX *parentMatrix, bool bUpdate = false);
			void		DrawFrame(LPD3DXFRAME frame) const;
			void		DrawMeshContainer(LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase) const;
public:
                        CXFileInstance( LPDIRECT3DDEVICE9 pDevice, CXFileEntity * CXFileEntity );
    virtual             ~CXFileInstance();

    virtual void        Cleanup();

          CXFileEntity* GetFileEntity();
            void        GetAnimController( LPD3DXANIMATIONCONTROLLER * ppAC );

    //virtual HRESULT     AdvanceTime( DOUBLE dTimeDelta, ID3DXAnimationCallbackHandler * pCH );
    virtual HRESULT     ResetTime();
    virtual HRESULT     Render3d();

	void FrameMove(float elapsedTime,const D3DXMATRIX *matWorld);
	void SetAnimationSet(UINT index);
	const char *GetAnimationSetName(UINT index);

	inline UINT GetIndexOfCurrentAnimationSet() const {return m_currentAnimationSet;}
	inline UINT GetNumAnimationSets() const {return m_numAnimationSets;}

    D3DXMATRIX  GetWorldTransform();
    void        SetWorldTransform( const D3DXMATRIX * pmxWorld );

	void AnimateFaster();
	void AnimateSlower();
	void NextAnimation();

};
